package user.service.impl;

import api.RemoteJudgeService;
import api.domain.vo.UserExeResultVO;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson2.JSON;
import core.constants.Constant;
import core.domain.Result;
import core.enums.ProgramLanguage;
import core.enums.QuestionResult;
import core.enums.ResultCode;
import core.exception.ServiceException;
import core.threadLocal.ThreadLocalUtils;
import api.domain.dto.JudgeSubmitDTO;
import api.domain.vo.UserQuestionResultVO;
import org.mybatis.spring.MyBatisSystemException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import user.domain.question.Question;
import user.domain.question.QuestionTestCase;
import user.domain.question.es.QuestionES;
import user.domain.user.UserSubmit;
import user.domain.user.dto.UserSubmitDTO;
import user.es.QuestionRepository;
import user.mapper.CQuestionMapper;
import user.mapper.UserSubmitMapper;
import user.mq.JudgeProducer;
import user.service.IUserQuestionService;

import java.util.List;

@Service
public class UserQuestionServiceImpl implements IUserQuestionService {

    @Autowired
    private QuestionRepository questionRepository;

    @Autowired
    private CQuestionMapper questionMapper;

    @Autowired
    private RemoteJudgeService remoteJudgeService;

    @Autowired
    private JudgeProducer judgeProducer;

    @Autowired
    private UserSubmitMapper userSubmitMapper;
    @Override
    public Result<UserQuestionResultVO> submit(UserSubmitDTO userSubmitDTO) {
        JudgeSubmitDTO judgeSubmitDTO;
        Integer programLanguage = userSubmitDTO.getProgramLanguage();
        if(ProgramLanguage.JAVA.getId().equals(programLanguage)){
            // 执行java代码
            judgeSubmitDTO = assembleUserQuestionResultVO(userSubmitDTO);
            return remoteJudgeService.doJudgeJavaCode(judgeSubmitDTO);
        } else {
            throw new ServiceException(ResultCode.PROGRAM_LANGUAGE_NOT_SUPPORT);
        }
    }

    @Override
    public boolean submitMq(UserSubmitDTO userSubmitDTO) {
        JudgeSubmitDTO judgeSubmitDTO;
        Integer programLanguage = userSubmitDTO.getProgramLanguage();
        if(ProgramLanguage.JAVA.getId().equals(programLanguage)){
            // 执行java代码
            judgeSubmitDTO = assembleUserQuestionResultVO(userSubmitDTO);
            judgeProducer.produceMsg(judgeSubmitDTO);
            return true;
        } else {
            throw new ServiceException(ResultCode.PROGRAM_LANGUAGE_NOT_SUPPORT);
        }
    }

    @Override
    public UserQuestionResultVO getExeResult(Long examId, Long questionId, String currentTime) {
        Long userId = ThreadLocalUtils.get(Constant.USER_ID, Long.class);
        UserSubmit userSubmit;
        try {
             userSubmit = userSubmitMapper.selectCurrentExeResult(userId, examId, questionId, currentTime);
        } catch (MyBatisSystemException e){
            throw new ServiceException(ResultCode.ERROR);
        }
        UserQuestionResultVO resultVO = new UserQuestionResultVO();
        if(userSubmit == null) {
            resultVO.setPass(QuestionResult.IN_JUDGE.getResult());
        } else {
            resultVO.setPass(userSubmit.getPass());
            resultVO.setExeMessage(userSubmit.getExeMessage());
            if (StrUtil.isNotEmpty(userSubmit.getCaseJudgeRes())) {
                resultVO.setUserExeResultVOList(JSON.parseArray(userSubmit.getCaseJudgeRes(), UserExeResultVO.class));
            }
        }
        return resultVO;
    }

    private JudgeSubmitDTO assembleUserQuestionResultVO(UserSubmitDTO userSubmitDTO) {
        Long questionId = userSubmitDTO.getQuestionId();
        JudgeSubmitDTO judgeSubmitDTO = new JudgeSubmitDTO();
        QuestionES questionES = questionRepository.findById(questionId).orElse(null);
        if(questionES != null) {
            BeanUtil.copyProperties(questionES, judgeSubmitDTO);
        } else {
            Question question = questionMapper.selectById(questionId);
            BeanUtil.copyProperties(question, judgeSubmitDTO);
            questionES = new QuestionES();
            BeanUtil.copyProperties(question, questionES);
            questionRepository.save(questionES);
        }
        judgeSubmitDTO.setUserId(ThreadLocalUtils.get(Constant.USER_ID, Long.class));
        judgeSubmitDTO.setExamId(userSubmitDTO.getExamId());
        judgeSubmitDTO.setProgramLanguage(userSubmitDTO.getProgramLanguage());
        judgeSubmitDTO.setUserCode(codeConnect(userSubmitDTO.getUserCode(), questionES.getMainFunc()));
        List<QuestionTestCase> list = JSONUtil.toList(questionES.getQuestionCase(), QuestionTestCase.class);
        judgeSubmitDTO.setInputList(list.stream().map(QuestionTestCase::getInput).toList());
        judgeSubmitDTO.setOutputList(list.stream().map(QuestionTestCase::getOutput).toList());
        return judgeSubmitDTO;
    }

    private String codeConnect(String userCode, String mainFunc){
        String targetCharacter = "}";
        int targetIndex = userCode.lastIndexOf(targetCharacter);
        if(targetIndex != -1){
            return userCode.substring(0, targetIndex) + "\n" + mainFunc + "\n" + userCode.substring(targetIndex) + "\n";
        }
        throw new ServiceException(ResultCode.FAILED);
    }
}
